package com.gz.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gz.dao.TestPaperMapper;
import com.gz.dto.*;
import com.gz.entity.*;
import com.gz.service.*;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.gz.vo.StuLabelQuestionRes;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * (TestPaper)表服务实现类
 *
 * @author makejava
 * @since 2024-02-23 17:02:04
 */
@Service
public class TestPaperServiceImpl implements TestPaperService {
    @Value("${app.aiPaperQuestionCnt}")
    private String aiPaperQuestionCnt;
    @Value("${app.aiPaperTotalScore}")
    private String aiPaperTotalScore;
    @Autowired
    private TestPaperMapper testPaperDao;
    @Autowired
    private QuestionService questionService;
    @Autowired
    private PaperQuestionService paperQuestionService;
    @Autowired
    private StudentQuestionTagWeightsService studentQuestionTagWeightsService;
    @Autowired
    private LabelInfoService labelInfoService;
    @Autowired
    private SuserService suserService;
    @Autowired
    private TestPaperService testPaperService;
    @Autowired
    private PaperUserService paperUserService;
    @Autowired
    private UserAnswersService userAnswersService;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public TestPaper queryById(Integer id) {
        return testPaperDao.queryById(id);
    }

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public List<Question> queryPaperDetail(Integer id) {
        List<Question> questions = testPaperDao.queryPaperDetail(id);
        questions.forEach(a -> {
            List<LabelInfo> labels = a.getLabels();
            List<Integer> labelIds = labels.stream().map(LabelInfo::getId).distinct()
                    .collect(Collectors.toList());
            a.setQuestionLabelIds(labelIds);
            List<String> labelNms = labels.stream().map(LabelInfo::getLabelName).distinct()
                    .collect(Collectors.toList());
            a.setQuestionLabels(labelNms);
        });
        return questions;
    }

    /**
     * 分页查询
     *
     * @param dto 筛选条件
     * @return 查询结果
     */
    @Override
    public PageData queryByPage(TestPaperDto dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<TestPaper> list = testPaperDao.queryAll(dto);
        PageInfo<TestPaper> pageInfo = new PageInfo<>(list);
        return new PageData<>(pageInfo.getTotal(), list);
    }
    @Override
    public PageData queryPageSendLog(TestPaperDto dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<TestPaperLog> list = testPaperDao.queryAllSLog(dto);
        PageInfo<TestPaperLog> pageInfo = new PageInfo<>(list);
        return new PageData<>(pageInfo.getTotal(), list);
    }

    /**
     * 分页查询
     *
     * @param dto 筛选条件
     * @return 查询结果
     */
    @Override
    public List<TestPaper> queryAll(TestPaperDto dto) {
        List<TestPaper> list = testPaperDao.queryAll(dto);
        return list;
    }

    /**
     * 新增数据
     *
     * @param testPaper 实例对象
     * @return 实例对象
     */
    @Override
    public TestPaper insert(TestPaper testPaper) {
        testPaper.setEnteredQtCnt(0);
        if(1==testPaper.getPaperType()&&null!=testPaper.getQuestionCount()){
            /** 手动试卷总分等于题目总数乘以答对得分数 */
            testPaper.setTotalScore(new BigDecimal(testPaper.getQuestionCount()).multiply(testPaper.getRightScore()).setScale(2, BigDecimal.ROUND_HALF_UP));
        }
        testPaper.setCrtDt(new Date());
        testPaper.setOptDt(new Date());
        testPaperDao.insert(testPaper);
        return testPaper;
    }

    /**
     * 生成ai试卷逻辑
     *
     * @param aiPaperInsertDto 实例对象
     * @return 实例对象
     */
    @Override
    @Transactional
    public List<TestPaper> handleLogicAutoPaper(AiPaperInsertDto aiPaperInsertDto) {
        List<TestPaper> tps = new ArrayList<>();
        /** 先拿到对应科目所有题目标签 或老师指定标签 */
        List<Integer> userIds = aiPaperInsertDto.getUserIds();
        LabelInfoDto lDto = new LabelInfoDto();
        /** 若老师指定标签集合不为空则智能试卷题目类型基于老师指定题目标签类型，为空则为所有标签 */
        if (!CollectionUtils.isEmpty(aiPaperInsertDto.getQuestionLabelIds())) {
            lDto.setIds(aiPaperInsertDto.getQuestionLabelIds());
        }
        lDto.setBlGrade(aiPaperInsertDto.getGrade());
        lDto.setBlLevel(aiPaperInsertDto.getLevel());
        lDto.setSubject(aiPaperInsertDto.getSubject());
        List<LabelInfo> labelInfos = labelInfoService.queryAll(lDto);
        /** 拿到卷子所有题目标签 */
        List<StudentQuestionTagWeights> orgAllWeights = new ArrayList<>();
        labelInfos.stream().forEach(a -> {
            StudentQuestionTagWeights itemLabelWeights = new StudentQuestionTagWeights();
            itemLabelWeights.setTag(a.getId());
            /** 此时所有标签权重无学生id */
            orgAllWeights.add(itemLabelWeights);
        });
        userIds.stream().forEach(a -> {
            /** 先根据学生信息生成题目试卷框架 */
            Suser suser = suserService.queryById(a);
            TestPaper testPaper = new TestPaper();
            Date now = new Date();
            String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now);
            /** 智能试卷名称=学生姓名-时间-科目智能试卷 */
            testPaper.setPaperName(suser.getUsername() + "-" + format + "-" + aiPaperInsertDto.getSubject() + "智能试卷");
            /** 试卷状态 */
            testPaper.setStatus(1);
            testPaper.setPaperType(2);
            testPaper.setSubject(aiPaperInsertDto.getSubject());
            testPaper.setGrade(aiPaperInsertDto.getGrade());
            testPaper.setLevel(aiPaperInsertDto.getLevel());
            testPaper.setDueTime(90.0);
            if(null!=aiPaperInsertDto.getRId()&&2==aiPaperInsertDto.getRId()&&null!=aiPaperInsertDto.getUId()){
                testPaper.setCrtId(aiPaperInsertDto.getUId());
            }
            /** 插入试卷用户关系 */
            testPaperService.insert(testPaper);
            PaperUser paperUser = new PaperUser();
            paperUser.setStatus(1);
            paperUser.setPaperId(testPaper.getId() + "");
            paperUser.setUserId(a + "");
            paperUser.setCrtDt(new Date());
            paperUser.setOptDt(new Date());
            if (null != testPaper.getCrtId()) {
                paperUser.setCrtId(testPaper.getCrtId());
            }
            paperUserService.insert(paperUser);
            tps.add(testPaper);
            /** new所有标签权重 */
            List<StudentQuestionTagWeights> allWeights = orgAllWeights;
            allWeights.stream().forEach(q -> {
                /** 此时所有标签权重有学生id */
                q.setStudentId(a);
            });
            StudentQuestionTagWeightsDto sqtwd = new StudentQuestionTagWeightsDto();
            sqtwd.setStudentId(a);
            /** 拿到该学生的所有权重 */
            List<StudentQuestionTagWeights> studentQuestionTagWeights = studentQuestionTagWeightsService.queryAll(sqtwd);
            if (!CollectionUtils.isEmpty(studentQuestionTagWeights)) {
                for (StudentQuestionTagWeights eqw : allWeights) {
                    eqw.setStudentId(a);
                    /** 遍历学生错题权重数据，如果有错题权重，那学生错题权重为10+错题权重，如果该标签没有错题，那权重为初始值10 */
                    for (StudentQuestionTagWeights sqw : studentQuestionTagWeights) {
                        if (eqw.getTag() == sqw.getTag()) {
                            eqw.setErrorWeight(10 + sqw.getErrorWeight());
                        } else {
                            eqw.setErrorWeight(10);
                        }
                    }
                }
            }
            int totalCnt = 0;
            /** 已存在题目id集合 */
            List<Integer> existQuestinIds = new ArrayList<>();
            /** 拿到该学生各个标签应当对应的题目数 */
            List<StuLabelQuestionRes> stuLabelQuestionRes = this.calStuTagQuestionAndCont(allWeights);
            List<Question> aiQuestions = new ArrayList<>();
            /** 根据标签题目数量和占比拿到学生专属对应标签所有题目，不足则随意补充 */
            for (StuLabelQuestionRes itmRes : stuLabelQuestionRes) {
                QuestionDto dto = new QuestionDto();
                dto.setSubject(aiPaperInsertDto.getSubject());
                dto.setQuestionLabel(itmRes.getTagId() + "");
                dto.setCntSize(itmRes.getStuQuestionCnt());
                dto.setExistQuesrtionIds(existQuestinIds);
                List<Question> questions = questionService.queryAllLimit(dto);
                List<Integer> addIds = questions.stream().map(Question::getId).collect(Collectors.toList());
                existQuestinIds.addAll(addIds);
                aiQuestions.addAll(questions);
                /** 每种标签的题目加起来为按标签查询题目的总数 */
                totalCnt += questions.size();

            }
            /* 如果ai试卷需要题目数小于试卷应含题目数 */
            if (CollectionUtils.isNotEmpty(aiQuestions) && totalCnt < Integer.parseInt(aiPaperQuestionCnt)) {
                /** 获取ai试卷当中已存在题目id集合 */
                aiQuestions.stream().map(Question::getId).distinct()
                        .collect(Collectors.toList());
                Integer fillCnt = Integer.parseInt(aiPaperQuestionCnt) - totalCnt;
                QuestionDto dtoNew = new QuestionDto();
                dtoNew.setSubject(aiPaperInsertDto.getSubject());
                dtoNew.setLevel(aiPaperInsertDto.getLevel());
                dtoNew.setGrade(aiPaperInsertDto.getGrade());
                dtoNew.setExistQuesrtionIds(existQuestinIds);
                dtoNew.setCntSize(fillCnt);
                List<Question> notExistQuestions = questionService.queryAllLimit(dtoNew);
                aiQuestions.addAll(notExistQuestions);
            }
            List<PaperQuestion> paperQuestions = new ArrayList<>();
            /** 根据试卷框架id填充对应试卷题目 */
            for (Question aiQuest : aiQuestions) {
                PaperQuestion paperQuestion = new PaperQuestion();
                /** 绑定试卷框架id */
                paperQuestion.setPaperId(testPaper.getId() + "");
                /** 绑定题目id */
                paperQuestion.setQuestionId(aiQuest.getId() + "");
                BigDecimal worthSc = new BigDecimal(aiPaperTotalScore).divide(new BigDecimal(aiPaperQuestionCnt)).setScale(2, BigDecimal.ROUND_HALF_UP);
                paperQuestion.setWorthScore(worthSc + "");
                paperQuestion.setCrtDt(new Date());
                paperQuestion.setOptDt(new Date());
                paperQuestion.setCrtId(0);
                paperQuestion.setOptId(0);
                paperQuestions.add(paperQuestion);
            }
            /** 插入根据试卷框架id的对应试卷题目 */
            paperQuestionService.insertBatch(paperQuestions);
        });
        return tps;
    }

    @Override
    @Transactional
    public TestPaper handleFaultPaper(FaultPaperInsertDto faultPaperInsertDto) {
        /** 先查错题，如果没错题直接返回空 */
        List<Integer> fpQuests = new ArrayList<>();
        RecentFaultDto recentFaultDto = new RecentFaultDto();
        recentFaultDto.setSubject(faultPaperInsertDto.getSubject());
        recentFaultDto.setGrade(faultPaperInsertDto.getGrade());
        recentFaultDto.setLevel(faultPaperInsertDto.getLevel());
        recentFaultDto.setUserId(faultPaperInsertDto.getUserid()+"");
        List<UserAnswers> faultQuestions = new ArrayList<>();
        faultQuestions = userAnswersService.queryRecentFault(recentFaultDto);
        QuestionDto dtoNew = new QuestionDto();
        if (CollectionUtils.isNotEmpty(faultQuestions)) {
            List<Integer> ufqs = faultQuestions.stream().map(UserAnswers::getQuestionId).collect(Collectors.toList());
            /** 如果不为空就直接插入题目 */
            fpQuests.addAll(ufqs);
        }else {
            return null;
        }
        /** 创建试卷 */
        TestPaper testPaper = new TestPaper();
        Date now = new Date();
        String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now);
        /** 错题试卷名称=学生姓名-时间-科目错题试卷 */
        testPaper.setPaperName(faultPaperInsertDto.getUsername() + "-" + format + "-" + faultPaperInsertDto.getSubject() + "错题试卷");
        /** 试卷状态 */
        testPaper.setStatus(1);
        testPaper.setPaperType(3);
        /** 卷子总分等于试卷题目是乘以4 */
        BigDecimal faultTotalScore = new BigDecimal(4).multiply(new BigDecimal(faultQuestions.size())).setScale(2, BigDecimal.ROUND_HALF_UP);
        testPaper.setTotalScore(faultTotalScore);
        testPaper.setSubject(faultPaperInsertDto.getSubject());
        testPaper.setGrade(faultPaperInsertDto.getGrade());
        testPaper.setLevel(faultPaperInsertDto.getLevel());
        /** 插入试卷框架 */
        testPaperService.insert(testPaper);
        /** 插入试卷用户关系（发卷） */
        testPaperService.insert(testPaper);
        PaperUser paperUser = new PaperUser();
        paperUser.setStatus(1);
        paperUser.setPaperId(testPaper.getId() + "");
        paperUser.setUserId(faultPaperInsertDto.getUserid()+"");
        paperUser.setCrtDt(new Date());
        paperUser.setOptDt(new Date());
        if (null != testPaper.getCrtId()) {
            paperUser.setCrtId(testPaper.getCrtId());
        }
        paperUserService.insert(paperUser);
        /** 试卷填充题目插入试卷题目关系表 */
        List<PaperQuestion> paperQuestions = new ArrayList<>();
        /** 根据试卷框架id填充对应试卷题目 */
        for (Integer fauQuestId : fpQuests) {
            PaperQuestion paperQuestion = new PaperQuestion();
            /** 绑定试卷框架id */
            paperQuestion.setPaperId(testPaper.getId() + "");
            /** 绑定题目id */
            paperQuestion.setQuestionId(fauQuestId + "");
            /** 满分=题目数乘以4，单题4分 */
            BigDecimal worthSc = new BigDecimal(4);
            paperQuestion.setWorthScore(worthSc + "");
            paperQuestion.setCrtDt(new Date());
            paperQuestion.setOptDt(new Date());
            paperQuestion.setCrtId(0);
            paperQuestion.setOptId(0);
            paperQuestions.add(paperQuestion);
        }
        /** 插入根据试卷框架id的对应试卷题目 */
        int i = paperQuestionService.insertBatch(paperQuestions);
        return testPaper;
    }

    public List<StuLabelQuestionRes> calStuTagQuestionAndCont(List<StudentQuestionTagWeights> studentQuestionTagWeights) {
        List<StuLabelQuestionRes> stuLabelQuestionResList = new ArrayList<>();
        int totalWeight = studentQuestionTagWeights.stream()
                .mapToInt(StudentQuestionTagWeights::getErrorWeight) // 将User对象转换为int类型的Stream
                .sum();
        for (StudentQuestionTagWeights sqItem : studentQuestionTagWeights) {
            StuLabelQuestionRes wtRes = new StuLabelQuestionRes();
            wtRes.setTagId(sqItem.getTag());
//            BigDecimal qlShare1 = BigDecimal.valueOf(sqItem.getErrorWeight() / totalWeight).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal qlShare2 = new BigDecimal(sqItem.getErrorWeight()).divide(new BigDecimal(totalWeight), 2, BigDecimal.ROUND_HALF_UP);
//            System.out.println("qlShare1-->"+qlShare1);
            System.out.println("qlShare2-->" + qlShare2);
            /** 计算每种标签的占比 */
            wtRes.setQlShare(qlShare2);
            /** 计算每种标签题目的数量 */
            BigDecimal result = new BigDecimal(aiPaperQuestionCnt).multiply(wtRes.getQlShare()).setScale(0, BigDecimal.ROUND_HALF_UP);
            wtRes.setStuQuestionCnt(result.intValue());
            stuLabelQuestionResList.add(wtRes);
        }
        System.out.println(aiPaperQuestionCnt);
        /** 调用逻辑处理组成‘aiPaperQuestionCnt’的卷子 */
        List<StuLabelQuestionRes> stuLabelQuestionRes = handleStuWeightQuestCntList(stuLabelQuestionResList, Integer.parseInt(aiPaperQuestionCnt));
        /** 处理后哥标签的题目数总和为25 */
        return stuLabelQuestionRes;
    }

    /**
     * 从占比最小的补齐
     */
    public static List<StuLabelQuestionRes> handleStuWeightQuestCntList(List<StuLabelQuestionRes> list, Integer n) {
        Collections.sort(list, Comparator.comparingInt(StuLabelQuestionRes::getStuQuestionCnt));
        list.stream()
                .forEach(item -> System.out.println("题目调整前标签id和对应数量before:" + item.getTagId() + "-->" + item.getStuQuestionCnt()));
        // 2. 计算总和
        int total = 0;
        for (StuLabelQuestionRes item : list) {
            total += item.getStuQuestionCnt();
        }

        // 3. 调整或补齐
        if (total > n) {
            // 需要调整，从最小的开始减少
            int diff = total - n;
            for (StuLabelQuestionRes item : list) {
                if (diff <= 0) {
                    break;
                }
                if (item.getStuQuestionCnt() > 0) {
                    int toSubtract = Math.min(diff, item.getStuQuestionCnt());
                    item.setStuQuestionCnt(item.getStuQuestionCnt() - toSubtract);
                    diff -= toSubtract;
                }
            }
        } else {
            // 需要补齐，从最小的开始增加
            int toAdd = n - total;
            int currentAdded = 0;
            for (int i = 0; i < list.size() && currentAdded < toAdd; i++) {
                StuLabelQuestionRes item = list.get(i);
                int canAdd = toAdd - currentAdded;
                int addToThis = Math.min(canAdd, Integer.MAX_VALUE - item.getStuQuestionCnt()); // 防止溢出
                item.setStuQuestionCnt(item.getStuQuestionCnt() + addToThis);
                currentAdded += addToThis;
            }
        }
        list.stream()
                .forEach(item -> System.out.println("题目调整后标签id和对应数量" + item.getTagId() + "-->" + item.getStuQuestionCnt()));
        return list;
    }

    /**
     * 从占比最大的补齐
     */
    public static List<StuLabelQuestionRes> handleStuWeightQuestCntList2(List<StuLabelQuestionRes> list, int n) {
        // 1. 按stuQuestionCnt排序
        Collections.sort(list, Comparator.comparingInt(StuLabelQuestionRes::getStuQuestionCnt));
        list.stream()
                .forEach(item -> System.out.println("题目调整前标签id和对应数量before:" + item.getTagId() + "-->" + item.getStuQuestionCnt()));

        // 2. 计算总和
        int total = list.stream().mapToInt(StuLabelQuestionRes::getStuQuestionCnt).sum();

        // 3. 如果总和小于n，从后向前增加题目数
        if (total < n) {
            int diff = n - total;
            for (int i = list.size() - 1; i >= 0 && diff > 0; i--) {
                if (list.get(i).getStuQuestionCnt() + diff > list.get(i).getStuQuestionCnt()) {
                    int add = Math.min(diff, 1); // 假设每次最多只能增加一个
                    list.get(i).setStuQuestionCnt(list.get(i).getStuQuestionCnt() + add);
                    diff -= add;
                }
            }
        }
        // 4. 如果总和大于n，从前往后减少题目数（这里逻辑较复杂，可能需要更具体的策略）
        else if (total > n) {
            int diff = total - n;
            for (int i = 0; i < list.size() && diff > 0; i++) {
                if (list.get(i).getStuQuestionCnt() - diff >= 0) {
                    int reduce = Math.min(diff, list.get(i).getStuQuestionCnt());
                    list.get(i).setStuQuestionCnt(list.get(i).getStuQuestionCnt() - reduce);
                    diff -= reduce;
                } else {
                    // 如果需要减少的数值大于当前值，则直接设置为0，并从diff中减去当前值
                    list.get(i).setStuQuestionCnt(0);
                    diff -= list.get(i).getStuQuestionCnt(); // 此时为0
                }
            }
        }
        list.stream()
                .forEach(item -> System.out.println("题目调整后标签id和对应数量" + item.getTagId() + "-->" + item.getStuQuestionCnt()));
        return list;
    }
    /** 智能补齐测试 */
//    public static void main(String[] args) {
//        List<StuLabelQuestionRes> list = new ArrayList<>();
//        StuLabelQuestionRes res1= new StuLabelQuestionRes();
//        res1.setTagId(1);
//        res1.setStuQuestionCnt(3);
//        StuLabelQuestionRes res2= new StuLabelQuestionRes();
//        res2.setTagId(2);
//        res2.setStuQuestionCnt(2);
//        StuLabelQuestionRes res3= new StuLabelQuestionRes();
//        res3.setTagId(3);
//        res3.setStuQuestionCnt(3);
//        StuLabelQuestionRes res4= new StuLabelQuestionRes();
//        res4.setTagId(4);
//        res4.setStuQuestionCnt(2);
//        list.add(res1);
//        list.add(res2);
//        list.add(res3);
//        list.add(res4);
//        List<StuLabelQuestionRes> stuLabelQuestionRes = handleStuWeightQuestCntList2(list, 12);
//        System.out.println(JSONObject.toJSONString(stuLabelQuestionRes));
//    }

    /**
     * 修改数据
     *
     * @param testPaper 实例对象
     * @return 实例对象
     */
    @Override
    public TestPaper update(TestPaper testPaper) {
        testPaper.setOptDt(new Date());
        testPaperDao.update(testPaper);
        return queryById(testPaper.getId());
    }

    /**
     * 批量修改数据
     *
     * @param list 实例对象
     * @return 实例对象
     */
    @Override
    public int updateBatch(List<TestPaper> list) {
        for (TestPaper testPaper : list) {
            testPaper.setOptDt(new Date());
        }
        return testPaperDao.updateBatch(list);
    }

    /**
     * 批量修改数据
     *
     * @param list 实例对象
     * @return 实例对象
     */
    @Override
    public int insertBatch(List<TestPaper> list) {
        return testPaperDao.insertBatch(list);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return testPaperDao.deleteById(id) > 0;
    }

    /**
     * 通过主键集合删除数据
     *
     * @param ids 主键集合
     * @return 是否成功
     */
    @Override
    public boolean deleteByIds(List<Integer> ids) {
        return testPaperDao.deleteByIds(ids) > 0;
    }
}
